#pragma once

#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

using namespace SemModule;
using namespace MutexModule;

static const int gcap = 5;

template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _cap(cap),
          _rq(cap), //_rq = std::vector<T>(cap); // 初始化列表写法更高效
          _blank_sem(cap),
          _p_step(0),
          _data_sem(0),
          _c_step(0)
    {
    }
    void Equeue(const T &in)
    {
        // 1. 申请信号量,将信号量减1
        _blank_sem.P();
        {
            LockGuard lockguard(_cmutex);
            // 2. 生产
            _rq[_p_step] = in;
            // 3. 更新下标
            ++_p_step;
            // 4. 维持环形特性
            _p_step %= _cap;
        }
        _data_sem.V(); // 将数据个数+1
    }
    void Pop(T *out)
    {
        // 消费者
        //  1. 申请信号量，数据信号量
        _data_sem.P(); // 如果没有数据，线程将会在此处被阻塞
        {
            LockGuard lockguard(_pmutex);
            // 2. 消费
            *out = _rq[_c_step];
            // 3. 更新下标
            ++_c_step;
            // 4. 同上
            _c_step %= _cap;
        }

        _blank_sem.V();
    }
    ~RingQueue() {}

private:
    std::vector<T> _rq;
    int _cap;

    // 消费者
    Sem _blank_sem;
    int _p_step;
    // 生产者
    Sem _data_sem;
    int _c_step;

    Mutex _cmutex;
    Mutex _pmutex;
};